package com.atguigu.zk;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

public class ZkClient {

    // 注意，不能存在空格
    // 如果zk服务配置文件中的集群配置为域名，那么这里也必须为域名，且在hosts配置好映射。
    // 一定要与配置文件保持一致，才能连接成功。
    private String connectString = "lc01:2181,lc02:2181,lc03:2181";
//    private String connectString = "192.168.200.11:2181,192.168.200.12:2181,192.168.200.13:2181";

    // 响应超时时间。请求多久后无响应便认为连接失效
    private int sessionTimeOut = 2000;
    private ZooKeeper zooKeeper = null;

    @Before // 其它@Test运行前自动运行
    public void init() throws IOException {
        zooKeeper = new ZooKeeper(connectString, sessionTimeOut, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                System.out.println("---------触发监听器开始----------");
                List<String> children = null;
                try {
                    children = zooKeeper.getChildren("/", true); // 监听器只能生效一次，设置为true，这里会再次触发监听注册，循环往复。
                    for (String child : children) {
                        System.out.println(child);
                    }
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("---------触发监听器结束----------");
                }

            }
        });
    }

    // 创建子节点
    @Test
    public void create() throws KeeperException, InterruptedException {
        // 参数 1：要创建的节点的路径； 参数 2：节点数据 ； 参数 3：节点权限 ； 参数 4：节点的类型
        // Ids.OPEN_ACL_UNSAFE 允许所有人访问该节点
        // CreateMode.PERSISTENT 持久化节点
        // CreateMode.PERSISTENT_SEQUENTIAL 持久化带序号节点
        // CreateMode.EPHEMERAL 临时节点
        // CreateMode.EPHEMERAL_SEQUENTIAL 临时带序号节点
        String s = zooKeeper.create("/t11/t21", "t21".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println("获取返回结果："+s); // /t11/t21
    }

    // 获取子节点，并监听子节点的变化
    // 第一次手动获取子节点列表，后面全部由监听器来自动获取变化
    @Test
    public void getChildren() throws KeeperException, InterruptedException {
        // 源码：this.getChildren(path, watch ? this.watchManager.defaultWatcher : null);
        // true 标识向服务器注册我们设置的默认监听器，false 监听器为空。
        // 该方法运行时，会先触发监听器并执行对应处理逻辑，再执行该方法后续代码
        List<String> children = zooKeeper.getChildren("/", true); // 即使设置为false,监听器中的代码依然会被优先运行一次
        Thread.sleep(2l);
        for (String child : children) {
            System.out.println("首次获取" + child);
        }
        Thread.sleep(2l);
        // 延时阻塞，保持线程不会终结
        Thread.sleep(Long.MAX_VALUE);

    }

    @Test
    public void checkNodeExist() throws KeeperException, InterruptedException {
        Stat exists = zooKeeper.exists("/t11", false); // 即使设置为false,监听器中的代码依然会被优先运行一次
        System.out.println(exists == null ? "目标节点不存在" : "目标节点存在");
    }


}
